package com.kexilo.core.common.config;

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import javax.sql.DataSource;

/**
 * 数据库优化配置
 * 提供数据库连接池优化和性能监控配置
 * 
 * @author Kexilo
 */
@Configuration
public class DatabaseOptimizationConfig {
    
    private static final Logger log = LoggerFactory.getLogger(DatabaseOptimizationConfig.class);
    
    /**
     * 优化的HikariCP数据源配置
     * 根据生产环境最佳实践配置连接池参数
     */
    @Bean
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource.hikari")
    @ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.zaxxer.hikari.HikariDataSource", matchIfMissing = true)
    public DataSource optimizedDataSource() {
        log.info("配置优化的HikariCP数据源...");
        
        HikariConfig config = new HikariConfig();
        
        // 基础连接配置
        config.setJdbcUrl(getJdbcUrl());
        config.setUsername(getUsername());
        config.setPassword(getPassword());
        config.setDriverClassName(getDriverClassName());
        
        // 连接池大小优化
        // 最小空闲连接数：保持一定数量的连接避免频繁创建
        config.setMinimumIdle(getMinimumIdle());
        // 最大连接数：根据应用负载和数据库能力设置
        config.setMaximumPoolSize(getMaximumPoolSize());
        
        // 连接超时配置
        // 连接超时：客户端等待连接的最大时间
        config.setConnectionTimeout(getConnectionTimeout());
        // 空闲超时：连接在池中空闲的最大时间
        config.setIdleTimeout(getIdleTimeout());
        // 连接最大生命周期：连接的最大存活时间
        config.setMaxLifetime(getMaxLifetime());
        
        // 连接验证配置
        // 连接测试查询
        config.setConnectionTestQuery("SELECT 1");
        // 验证超时时间
        config.setValidationTimeout(getValidationTimeout());
        
        // 性能优化配置
        // 是否自动提交
        config.setAutoCommit(true);
        // 连接只读标识（对于读写分离场景）
        config.setReadOnly(false);
        // 事务隔离级别（使用数据库默认）
        config.setTransactionIsolation("TRANSACTION_READ_COMMITTED");
        
        // 连接池名称（便于监控）
        config.setPoolName("KexiloHikariPool");
        
        // JMX监控启用
        config.setRegisterMbeans(true);
        
        // 泄露检测配置
        // 连接泄露检测阈值（毫秒）
        config.setLeakDetectionThreshold(getLeakDetectionThreshold());
        
        // PostgreSQL特定优化
        config.addDataSourceProperty("cachePrepStmts", "true");
        config.addDataSourceProperty("prepStmtCacheSize", "250");
        config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
        config.addDataSourceProperty("useServerPrepStmts", "true");
        config.addDataSourceProperty("useLocalSessionState", "true");
        config.addDataSourceProperty("rewriteBatchedStatements", "true");
        config.addDataSourceProperty("cacheResultSetMetadata", "true");
        config.addDataSourceProperty("cacheServerConfiguration", "true");
        config.addDataSourceProperty("elideSetAutoCommits", "true");
        config.addDataSourceProperty("maintainTimeStats", "false");
        
        // 应用程序名称（便于数据库监控）
        config.addDataSourceProperty("ApplicationName", "Kexilo-System");
        
        HikariDataSource dataSource = new HikariDataSource(config);
        
        log.info("HikariCP数据源配置完成 - 最小连接:{}, 最大连接:{}, 连接超时:{}ms", 
                config.getMinimumIdle(), config.getMaximumPoolSize(), config.getConnectionTimeout());
        
        return dataSource;
    }
    
    // 配置属性获取方法（可以从配置文件读取）
    
    private String getJdbcUrl() {
        return System.getProperty("spring.datasource.url", 
                "jdbc:postgresql://localhost:5432/kexilo");
    }
    
    private String getUsername() {
        return System.getProperty("spring.datasource.username", "kexilo");
    }
    
    private String getPassword() {
        return System.getProperty("spring.datasource.password", "kexilo123");
    }
    
    private String getDriverClassName() {
        return "org.postgresql.Driver";
    }
    
    private int getMinimumIdle() {
        // 生产环境建议值：5-10
        return Integer.parseInt(System.getProperty("spring.datasource.hikari.minimum-idle", "5"));
    }
    
    private int getMaximumPoolSize() {
        // 生产环境建议值：根据CPU核心数和并发量设置
        // 公式：((core_count * 2) + effective_spindle_count)
        int cores = Runtime.getRuntime().availableProcessors();
        int defaultPoolSize = Math.max(10, cores * 2);
        return Integer.parseInt(System.getProperty("spring.datasource.hikari.maximum-pool-size", 
                String.valueOf(defaultPoolSize)));
    }
    
    private long getConnectionTimeout() {
        // 连接超时：30秒
        return Long.parseLong(System.getProperty("spring.datasource.hikari.connection-timeout", "30000"));
    }
    
    private long getIdleTimeout() {
        // 空闲超时：10分钟
        return Long.parseLong(System.getProperty("spring.datasource.hikari.idle-timeout", "600000"));
    }
    
    private long getMaxLifetime() {
        // 连接最大生命周期：30分钟
        return Long.parseLong(System.getProperty("spring.datasource.hikari.max-lifetime", "1800000"));
    }
    
    private long getValidationTimeout() {
        // 验证超时：5秒
        return Long.parseLong(System.getProperty("spring.datasource.hikari.validation-timeout", "5000"));
    }
    
    private long getLeakDetectionThreshold() {
        // 泄露检测阈值：60秒（0表示禁用）
        return Long.parseLong(System.getProperty("spring.datasource.hikari.leak-detection-threshold", "60000"));
    }
    
    /**
     * 数据库性能监控配置
     */
    @Bean
    @ConditionalOnProperty(name = "kexilo.database.monitoring.enabled", havingValue = "true", matchIfMissing = false)
    public DatabasePerformanceMonitor databasePerformanceMonitor() {
        log.info("启用数据库性能监控...");
        return new DatabasePerformanceMonitor();
    }
    
    /**
     * 数据库性能监控器
     */
    public static class DatabasePerformanceMonitor {
        
        private static final Logger monitor = LoggerFactory.getLogger("DATABASE_MONITOR");
        
        /**
         * 监控连接池状态
         */
        public void monitorConnectionPool(HikariDataSource dataSource) {
            if (dataSource != null) {
                monitor.info("连接池状态 - 活跃连接:{}, 空闲连接:{}, 等待连接:{}, 总连接:{}",
                        dataSource.getHikariPoolMXBean().getActiveConnections(),
                        dataSource.getHikariPoolMXBean().getIdleConnections(),
                        dataSource.getHikariPoolMXBean().getThreadsAwaitingConnection(),
                        dataSource.getHikariPoolMXBean().getTotalConnections());
            }
        }
        
        /**
         * 监控慢查询
         */
        public void logSlowQuery(String sql, long executionTime) {
            // 慢查询阈值：500ms
            final long SLOW_QUERY_THRESHOLD = 500;
            
            if (executionTime > SLOW_QUERY_THRESHOLD) {
                monitor.warn("慢查询检测 - 执行时间:{}ms, SQL:{}", executionTime, sql);
            }
        }
        
        /**
         * 监控数据库连接异常
         */
        public void logConnectionError(String operation, Exception e) {
            monitor.error("数据库连接异常 - 操作:{}, 异常:{}", operation, e.getMessage());
        }
    }
}
